home *** CD-ROM | disk | FTP | other *** search
/ Aminet 40 / Aminet 40 (2000)(Schatztruhe)[!][Dec 2000].iso / Aminet / dev / lang / Python16.lha / Python-1.6 / Lib / Python1.6 / distutils / bcppcompiler.py < prev    next >
Encoding:
Python Source  |  2000-08-13  |  14.6 KB  |  393 lines

  1. """distutils.bcppcompiler
  2.  
  3. Contains BorlandCCompiler, an implementation of the abstract CCompiler class
  4. for the Borland C++ compiler.
  5. """
  6.  
  7. # This implementation by Lyle Johnson, based on the original msvccompiler.py
  8. # module and using the directions originally published by Gordon Williams.
  9.  
  10. # XXX looks like there's a LOT of overlap between these two classes:
  11. # someone should sit down and factor out the common code as
  12. # WindowsCCompiler!  --GPW
  13.  
  14. __revision__ = "$Id: bcppcompiler.py,v 1.5 2000/08/13 00:54:39 gward Exp $"
  15.  
  16.  
  17. import sys, os, string
  18. from distutils.errors import \
  19.      DistutilsExecError, DistutilsPlatformError, \
  20.      CompileError, LibError, LinkError
  21. from distutils.ccompiler import \
  22.      CCompiler, gen_preprocess_options, gen_lib_options
  23. from distutils.file_util import write_file
  24.  
  25.  
  26. class BCPPCompiler(CCompiler) :
  27.     """Concrete class that implements an interface to the Borland C/C++
  28.     compiler, as defined by the CCompiler abstract class.
  29.     """
  30.  
  31.     compiler_type = 'bcpp'
  32.  
  33.     # Just set this so CCompiler's constructor doesn't barf.  We currently
  34.     # don't use the 'set_executables()' bureaucracy provided by CCompiler,
  35.     # as it really isn't necessary for this sort of single-compiler class.
  36.     # Would be nice to have a consistent interface with UnixCCompiler,
  37.     # though, so it's worth thinking about.
  38.     executables = {}
  39.  
  40.     # Private class data (need to distinguish C from C++ source for compiler)
  41.     _c_extensions = ['.c']
  42.     _cpp_extensions = ['.cc', '.cpp', '.cxx']
  43.  
  44.     # Needed for the filename generation methods provided by the
  45.     # base class, CCompiler.
  46.     src_extensions = _c_extensions + _cpp_extensions
  47.     obj_extension = '.obj'
  48.     static_lib_extension = '.lib'
  49.     shared_lib_extension = '.dll'
  50.     static_lib_format = shared_lib_format = '%s%s'
  51.     exe_extension = '.exe'
  52.  
  53.  
  54.     def __init__ (self,
  55.                   verbose=0,
  56.                   dry_run=0,
  57.                   force=0):
  58.  
  59.         CCompiler.__init__ (self, verbose, dry_run, force)
  60.  
  61.         # These executables are assumed to all be in the path.
  62.         # Borland doesn't seem to use any special registry settings to
  63.         # indicate their installation locations.
  64.  
  65.         self.cc = "bcc32.exe"
  66.         self.link = "ilink32.exe"
  67.         self.lib = "tlib.exe"
  68.  
  69.         self.preprocess_options = None
  70.         self.compile_options = ['/tWM', '/O2', '/q', '/g0']
  71.         self.compile_options_debug = ['/tWM', '/Od', '/q', '/g0']
  72.  
  73.         self.ldflags_shared = ['/Tpd', '/Gn', '/q', '/x']
  74.         self.ldflags_shared_debug = ['/Tpd', '/Gn', '/q', '/x']
  75.         self.ldflags_static = []
  76.  
  77.  
  78.     # -- Worker methods ------------------------------------------------
  79.  
  80.     def compile (self,
  81.                  sources,
  82.                  output_dir=None,
  83.                  macros=None,
  84.                  include_dirs=None,
  85.                  debug=0,
  86.                  extra_preargs=None,
  87.                  extra_postargs=None):
  88.  
  89.         (output_dir, macros, include_dirs) = \
  90.             self._fix_compile_args (output_dir, macros, include_dirs)
  91.         (objects, skip_sources) = self._prep_compile (sources, output_dir)
  92.  
  93.         if extra_postargs is None:
  94.             extra_postargs = []
  95.  
  96.         pp_opts = gen_preprocess_options (macros, include_dirs)
  97.         compile_opts = extra_preargs or []
  98.         compile_opts.append ('-c')
  99.         if debug:
  100.             compile_opts.extend (self.compile_options_debug)
  101.         else:
  102.             compile_opts.extend (self.compile_options)
  103.         
  104.         for i in range (len (sources)):
  105.             src = sources[i] ; obj = objects[i]
  106.             ext = (os.path.splitext (src))[1]
  107.  
  108.             if skip_sources[src]:
  109.                 self.announce ("skipping %s (%s up-to-date)" % (src, obj))
  110.             else:
  111.                 if ext in self._c_extensions:
  112.                     input_opt = ""
  113.                 elif ext in self._cpp_extensions:
  114.                     input_opt = "-P"
  115.  
  116.                 src = os.path.normpath(src)
  117.                 obj = os.path.normpath(obj)
  118.                 
  119.                 output_opt = "-o" + obj
  120.                 self.mkpath(os.path.dirname(obj))
  121.  
  122.                 # Compiler command line syntax is: "bcc32 [options] file(s)".
  123.                 # Note that the source file names must appear at the end of
  124.                 # the command line.
  125.                 try:
  126.                     self.spawn ([self.cc] + compile_opts + pp_opts +
  127.                                 [input_opt, output_opt] +
  128.                                 extra_postargs + [src])
  129.                 except DistutilsExecError, msg:
  130.                     raise CompileError, msg
  131.  
  132.         return objects
  133.  
  134.     # compile ()
  135.  
  136.  
  137.     def create_static_lib (self,
  138.                            objects,
  139.                            output_libname,
  140.                            output_dir=None,
  141.                            debug=0,
  142.                            extra_preargs=None,
  143.                            extra_postargs=None):
  144.  
  145.         (objects, output_dir) = self._fix_object_args (objects, output_dir)
  146.         output_filename = \
  147.             self.library_filename (output_libname, output_dir=output_dir)
  148.  
  149.         if self._need_link (objects, output_filename):
  150.             lib_args = [output_filename, '/u'] + objects
  151.             if debug:
  152.                 pass                    # XXX what goes here?
  153.             if extra_preargs:
  154.                 lib_args[:0] = extra_preargs
  155.             if extra_postargs:
  156.                 lib_args.extend (extra_postargs)
  157.             try:
  158.                self.spawn ([self.lib] + lib_args)
  159.             except DistutilsExecError, msg:
  160.                raise LibError, msg
  161.         else:
  162.             self.announce ("skipping %s (up-to-date)" % output_filename)
  163.  
  164.     # create_static_lib ()
  165.     
  166.  
  167.     def link_shared_lib (self,
  168.                          objects,
  169.                          output_libname,
  170.                          output_dir=None,
  171.                          libraries=None,
  172.                          library_dirs=None,
  173.                          runtime_library_dirs=None,
  174.                          export_symbols=None,
  175.                          debug=0,
  176.                          extra_preargs=None,
  177.                          extra_postargs=None,
  178.                          build_temp=None):
  179.  
  180.         self.link_shared_object (objects,
  181.                                  self.shared_library_name(output_libname),
  182.                                  output_dir=output_dir,
  183.                                  libraries=libraries,
  184.                                  library_dirs=library_dirs,
  185.                                  runtime_library_dirs=runtime_library_dirs,
  186.                                  export_symbols=export_symbols,
  187.                                  debug=debug,
  188.                                  extra_preargs=extra_preargs,
  189.                                  extra_postargs=extra_postargs,
  190.                                  build_temp=build_temp)
  191.                     
  192.     
  193.     def link_shared_object (self,
  194.                             objects,
  195.                             output_filename,
  196.                             output_dir=None,
  197.                             libraries=None,
  198.                             library_dirs=None,
  199.                             runtime_library_dirs=None,
  200.                             export_symbols=None,
  201.                             debug=0,
  202.                             extra_preargs=None,
  203.                             extra_postargs=None,
  204.                             build_temp=None):
  205.  
  206.         # XXX this ignores 'build_temp'!  should follow the lead of
  207.         # msvccompiler.py
  208.  
  209.         (objects, output_dir) = self._fix_object_args (objects, output_dir)
  210.         (libraries, library_dirs, runtime_library_dirs) = \
  211.             self._fix_lib_args (libraries, library_dirs, runtime_library_dirs)
  212.  
  213.         if runtime_library_dirs:
  214.             self.warn ("I don't know what to do with 'runtime_library_dirs': "
  215.                        + str (runtime_library_dirs))
  216.         
  217.         if output_dir is not None:
  218.             output_filename = os.path.join (output_dir, output_filename)
  219.  
  220.         if self._need_link (objects, output_filename):
  221.  
  222.             if debug:
  223.                 ld_args = self.ldflags_shared_debug[:]
  224.             else:
  225.                 ld_args = self.ldflags_shared[:]
  226.  
  227.             # Borland C++ has problems with '/' in paths
  228.             objects = map(os.path.normpath, objects)
  229.             startup_obj = 'c0d32'
  230.             objects.insert(0, startup_obj)
  231.  
  232.             # either exchange python15.lib in the python libs directory against
  233.             # a Borland-like one, or create one with name bcpp_python15.lib 
  234.             # there and remove the pragmas from config.h  
  235.             libraries.append ('import32')
  236.             libraries.append ('cw32mt')
  237.  
  238.             # Create a temporary exports file for use by the linker
  239.             head, tail = os.path.split (output_filename)
  240.             modname, ext = os.path.splitext (tail)
  241.             temp_dir = os.path.dirname(objects[0]) # preserve tree structure
  242.             def_file = os.path.join (temp_dir, '%s.def' % modname)
  243.             contents = ['EXPORTS']
  244.             for sym in (export_symbols or []):
  245.                 contents.append('  %s=_%s' % (sym, sym))
  246.             self.execute(write_file, (def_file, contents),
  247.                          "writing %s" % def_file)
  248.  
  249.             # Start building command line flags and options.
  250.  
  251.             for l in library_dirs:
  252.                 ld_args.append("/L%s" % os.path.normpath(l)) 
  253.                 
  254.             ld_args.extend(objects)     # list of object files
  255.  
  256.             # XXX the command-line syntax for Borland C++ is a bit wonky;
  257.             # certain filenames are jammed together in one big string, but
  258.             # comma-delimited.  This doesn't mesh too well with the
  259.             # Unix-centric attitude (with a DOS/Windows quoting hack) of
  260.             # 'spawn()', so constructing the argument list is a bit
  261.             # awkward.  Note that doing the obvious thing and jamming all
  262.             # the filenames and commas into one argument would be wrong,
  263.             # because 'spawn()' would quote any filenames with spaces in
  264.             # them.  Arghghh!.  Apparently it works fine as coded...
  265.  
  266.             # name of dll file
  267.             ld_args.extend([',',output_filename])
  268.             # no map file and start libraries 
  269.             ld_args.append(',,')
  270.  
  271.             for lib in libraries:
  272.                 # see if we find it and if there is a bcpp specific lib 
  273.                 # (bcpp_xxx.lib)
  274.                 libfile = self.find_library_file(library_dirs, lib, debug)
  275.                 if libfile is None:
  276.                     ld_args.append(lib)
  277.                     # probably a BCPP internal library -- don't warn
  278.                     #    self.warn('library %s not found.' % lib)
  279.                 else:
  280.                     # full name which prefers bcpp_xxx.lib over xxx.lib
  281.                     ld_args.append(libfile)
  282.             # def file for export symbols
  283.             ld_args.extend([',',def_file])
  284.             
  285.             if extra_preargs:
  286.                 ld_args[:0] = extra_preargs
  287.             if extra_postargs:
  288.                 ld_args.extend(extra_postargs)
  289.  
  290.             self.mkpath (os.path.dirname (output_filename))
  291.             try:
  292.                 self.spawn ([self.link] + ld_args)
  293.             except DistutilsExecError, msg:
  294.                 raise LinkError, msg
  295.  
  296.         else:
  297.             self.announce ("skipping %s (up-to-date)" % output_filename)
  298.  
  299.     # link_shared_object ()
  300.  
  301.  
  302.     def link_executable (self,
  303.                          objects,
  304.                          output_progname,
  305.                          output_dir=None,
  306.                          libraries=None,
  307.                          library_dirs=None,
  308.                          runtime_library_dirs=None,
  309.                          debug=0,
  310.                          extra_preargs=None,
  311.                          extra_postargs=None):
  312.  
  313.         (objects, output_dir) = self._fix_object_args (objects, output_dir)
  314.         (libraries, library_dirs, runtime_library_dirs) = \
  315.             self._fix_lib_args (libraries, library_dirs, runtime_library_dirs)
  316.  
  317.         if runtime_library_dirs:
  318.             self.warn ("I don't know what to do with 'runtime_library_dirs': "
  319.                        + str (runtime_library_dirs))
  320.         
  321.         lib_opts = gen_lib_options (self,
  322.                                     library_dirs, runtime_library_dirs,
  323.                                     libraries)
  324.         output_filename = output_progname + self.exe_extension
  325.         if output_dir is not None:
  326.             output_filename = os.path.join (output_dir, output_filename)
  327.  
  328.         if self._need_link (objects, output_filename):
  329.  
  330.             if debug:
  331.                 ldflags = self.ldflags_shared_debug[1:]
  332.             else:
  333.                 ldflags = self.ldflags_shared[1:]
  334.  
  335.             ld_args = ldflags + lib_opts + \
  336.                       objects + ['/OUT:' + output_filename]
  337.  
  338.             if extra_preargs:
  339.                 ld_args[:0] = extra_preargs
  340.             if extra_postargs:
  341.                 ld_args.extend (extra_postargs)
  342.  
  343.             self.mkpath (os.path.dirname (output_filename))
  344.             try:
  345.                 self.spawn ([self.link] + ld_args)
  346.             except DistutilsExecError, msg:
  347.                 raise LinkError, msg
  348.         else:
  349.             self.announce ("skipping %s (up-to-date)" % output_filename)   
  350.     
  351.  
  352.     # -- Miscellaneous methods -----------------------------------------
  353.     # These are all used by the 'gen_lib_options() function, in
  354.     # ccompiler.py.
  355.  
  356.     def library_dir_option (self, dir):
  357.         return "-L" + dir
  358.  
  359.     def runtime_library_dir_option (self, dir):
  360.         raise DistutilsPlatformError, \
  361.               ("don't know how to set runtime library search path "
  362.                "for Borland C++")
  363.  
  364.     def library_option (self, lib):
  365.         return self.library_filename (lib)
  366.  
  367.  
  368.     def find_library_file (self, dirs, lib, debug=0):
  369.         # List of effective library names to try, in order of preference:
  370.         # bcpp_xxx.lib is better than xxx.lib
  371.         # and xxx_d.lib is better than xxx.lib if debug is set
  372.         #
  373.         # The "bcpp_" prefix is to handle a Python installation for people
  374.         # with multiple compilers (primarily Distutils hackers, I suspect
  375.         # ;-).  The idea is they'd have one static library for each
  376.         # compiler they care about, since (almost?) every Windows compiler
  377.         # seems to have a different format for static libraries.
  378.         if debug:
  379.             dlib = (lib + "_d")
  380.             try_names = ("bcpp_" + dlib, "bcpp_" + lib, dlib, lib)
  381.         else:
  382.             try_names = ("bcpp_" + lib, lib)
  383.  
  384.         for dir in dirs:
  385.             for name in try_names:
  386.                 libfile = os.path.join(dir, self.library_filename(name))
  387.                 if os.path.exists(libfile):
  388.                     return libfile
  389.         else:
  390.             # Oops, didn't find it in *any* of 'dirs'
  391.             return None
  392.  
  393.